package net.maxupeng.asm74.segment;

import net.maxupeng.asm74.AddressMode;
import net.maxupeng.asm74.MCodeDefModel;
import net.maxupeng.asm74.antlr.ASM74Parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProcSegment extends Segment {
    public final Map<Integer, List<String>> romLabelRefMap = new HashMap<>();
    public final List<ASM74Parser.LineContext> lineCtxs = new ArrayList<>();
    public final String name;

    public ProcSegment(ASM74Parser.ProgContext progCtx, String name) {
        super(progCtx);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public void output_rom(int[] romArray) {
        super.output_rom(romArray);
    }


    public static List<ProcSegment> parse(List<ASM74Parser.ProgContext> progCtxs) {
        List<ProcSegment> procs = new ArrayList<>();

        ProcSegment proc = new ProcSegment(null, "");
        for (ASM74Parser.ProgContext progCtx : progCtxs) {
            boolean isCodeSegment = false;
            for (ASM74Parser.LineContext lineCtx : progCtx.line()) {
                if (isCodeSegment && lineCtx.label() != null) {
                    String name = lineCtx.label().ID().getText();
                    proc.romLabelOffsetMap.put(name, proc.romSize);
                }

                if (lineCtx.cmd() != null) {
                    ASM74Parser.CmdContext cmdCtx = lineCtx.cmd();
                    String cmd = cmdCtx.getStart().getText();
                    if (cmd.equals(".segment")) {
                        isCodeSegment = cmdCtx.STRING().getText().trim().replaceAll("^\"|\"$", "").toUpperCase().equals("CODE");
                    }

                    if (isCodeSegment && cmd.equals(".proc")) {
                        String name = cmdCtx.ID().getText();
                        if (procs.stream().anyMatch(p -> p.getName().equals(name))) {
                            System.out.println("Duplicated proc: " + name);
                            System.exit(1);
                        }
                        proc = new ProcSegment(progCtx, name);
                        proc.romLabelOffsetMap.put(name, 0);

                        procs.add(proc);
                    }

                    if (isCodeSegment && cmd.equals("debug")) {
                        proc.lineCtxs.add(lineCtx);
                    }
                }

                if (isCodeSegment && lineCtx.opcode() != null) {
                    String amName = AddressMode.getAmName(lineCtx.am());
                    if ("direct_index".equals(amName)) amName = "direct";
                    else if ("index_indirect".equals(amName)) amName = "indirect";

                    proc.lineCtxs.add(lineCtx);
                    proc.romSize += MCodeDefModel.getInstructionLength(lineCtx.opcode().getText(), amName);
                }
            }
        }

        return procs;
    }
}